﻿using System.Drawing;
using System.Windows.Forms;
using System.Custom.Drawing;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace System.Custom.Window
{
   public partial class Window
   {
      private struct BoundsInfo
      {
         internal bool AutoSize;
         internal Rectangle Bounds;
      }

      bool FControlsPrepared;
      bool FAeroGlassEnabled;// = true;

      Control FAeroGlassExcludeControl;
      Collection<Control> FAeroControls;
      Dictionary<object, string> FCaptions;
      Dictionary<object, BoundsInfo> FDims;

      public event EventHandler AeroGlassEffectChanged;

      public Control AeroGlassExcludeControl
      {
         get
         {
            return FAeroGlassExcludeControl;
         }
         set
         {
            if (FAeroGlassExcludeControl == value) return;

            FAeroGlassExcludeControl = value;

            if (AeroGlassVisible) SetAeroGlassEffect(true);
         }
      }

      public bool AeroGlassEnabled
      {
         get
         {
            return FAeroGlassEnabled;
         }
         set
         {
            if (FAeroGlassEnabled == value) return;

            FAeroGlassEnabled = value;

            SetAeroGlassEffect(value);

            if (AeroGlassEffectChanged != null) AeroGlassEffectChanged.Invoke(this, EventArgs.Empty);
         }
      }

      public bool AeroGlassVisible
      {
         get
         {
            return FAeroGlassEnabled && AeroGlass.CompositionEnabled;
         }
      }

      private void SetAeroGlassEffect(bool enabled)
      {
         if (DesignMode || !AeroGlass.CompositionEnabled || !IsHandleCreated) return;

         FAeroGlassEnabled = enabled;

         if (!FControlsPrepared)
         {
            FAeroControls = new Collection<Control>();
            FCaptions = new Dictionary<object, string>();
            FDims = new Dictionary<object, BoundsInfo>();
            PrepareControlsForAeroGlassEffect(this);
            FControlsPrepared = true;
         }

         AeroGlass.ApplyEffect(this, FAeroGlassEnabled, FAeroGlassExcludeControl);

         foreach (Control c in FAeroControls)
         {
            if (c is Button)
            {
               //c.Text = AeroGlassVisible ? "" : FCaptions[c];
            }
            else if (c is Label)
            {
               Label control = c as Label;

               BoundsInfo b = FDims[c];

               if (AeroGlassVisible)
               {
                  control.AutoSize = false;
                  control.Width = 1;
                  control.Height = 1;
               }
               else
               {
                  if (b.AutoSize) control.AutoSize = b.AutoSize; else control.Bounds = b.Bounds;
               }
            }
            else if (c is ButtonBase)
            {
               ButtonBase control = c as ButtonBase;

               BoundsInfo b = FDims[c];

               if (AeroGlassVisible)
               {
                  control.AutoSize = false;
                  control.Width = 14;
               }
               else
               {
                  if (b.AutoSize) control.AutoSize = b.AutoSize; else control.Bounds = b.Bounds;
               }
            }
         }

         Refresh();
      }

      private void PrepareControlsForAeroGlassEffect(Control control)
      {
         foreach (Control c in control.Controls)
         {
            if (c == FAeroGlassExcludeControl)
            {
               if (c.BackColor == Color.Transparent) c.BackColor = BackColor;
            }
            else if (c is Button)
            {
               c.Paint += (o, e) =>
               {
                  if (!FControlsPrepared) return;

                  //if (AeroGlassVisible)
                  {
                     string text = FCaptions[o];
                     Button button = o as Button;
                     e.Graphics.DrawString(text, button.Font, Brushes.Black,
                        (button.Width - e.Graphics.MeasureString(text, button.Font).Width) / 2,
                        (button.Height - e.Graphics.MeasureString("A", button.Font).Height) / 2);
                  }
               };
               FCaptions[c] = c.Text;
               c.Text = "";
               //FAeroControls.Add(c);
            }
            else if (c is Label)
            {
               if (c.Parent != this) continue;

               c.Paint += (o, e) =>
               {
                  if (!FControlsPrepared) return;

                  Label label = o as Label;

                  if (AeroGlassVisible)
                  {
                     BoundsInfo b = FDims[o];
                     Rectangle r = b.Bounds;
                     r.Y += 0;
                     r.X += 3;
                     TextFormatFlags format = TextFormatFlags.Default;
                     if (label.TextAlign == ContentAlignment.TopCenter) format |= TextFormatFlags.HorizontalCenter;
                     else if (label.TextAlign == ContentAlignment.MiddleCenter) format |= (TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
                     if (label.AutoSize) format |= TextFormatFlags.SingleLine;
                     else format |= TextFormatFlags.WordBreak;
                     if (label.AutoEllipsis) format |= TextFormatFlags.EndEllipsis;
                     AeroGlass.DrawText(this, label.Text, label.Font, r, 12, format);
                  }
               };
               c.BackColor = Color.Transparent;
               FDims[c] = new BoundsInfo() { Bounds = c.Bounds, AutoSize = (c as Label).AutoSize };
               FAeroControls.Add(c);
            }
            else if (c is ButtonBase)
            {
               if (c.Parent != this) continue;

               c.Paint += (o, e) =>
               {
                  if (!FControlsPrepared) return;

                  ButtonBase button = o as ButtonBase;

                  if (AeroGlassVisible)
                  {
                     BoundsInfo b = FDims[o];
                     Rectangle r = b.Bounds;
                     r.Y += 1;
                     r.X += 19;
                     TextFormatFlags format = TextFormatFlags.Default;
                     if (button.TextAlign == ContentAlignment.TopCenter) format |= TextFormatFlags.HorizontalCenter;
                     else if (button.TextAlign == ContentAlignment.MiddleCenter) format |= (TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
                     if (button.AutoSize) format |= TextFormatFlags.SingleLine;
                     else format |= TextFormatFlags.WordBreak;
                     if (button.AutoEllipsis) format |= TextFormatFlags.EndEllipsis;
                     AeroGlass.DrawText(this, button.Text, button.Font, r, 12, format);
                  }
               };
               c.BackColor = Color.Transparent;
               FDims[c] = new BoundsInfo() { Bounds = c.Bounds, AutoSize = (c as ButtonBase).AutoSize };
               FAeroControls.Add(c);
            }
            else if (c.Controls.Count > 0)
            {
               PrepareControlsForAeroGlassEffect(c);
            }
         }
      }

      protected override void OnLoad(EventArgs e)
      {
         base.OnLoad(e);

         if (AeroGlassVisible) SetAeroGlassEffect(true);
      }

      protected override void OnPaint(PaintEventArgs e)
      {
         base.OnPaint(e);

         if (DesignMode == false)
         {
            if (AeroGlassVisible) AeroGlass.FillBlack(e.Graphics, e.ClipRectangle);
         }
      }

      protected override void OnResize(EventArgs e)
      {
         base.OnResize(e);

         if (FControlsPrepared && AeroGlassVisible) AeroGlass.ApplyEffect(this, true, FAeroGlassExcludeControl);
      }
   }
}
